package com.mmall.pay.service.impl;

import cn.hutool.core.date.DateUtil;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.mmall.common.constant.Constant;
import com.mmall.common.util.BeanUtil;
import com.mmall.pay.bean.MmallPayConfig;
import com.mmall.pay.enums.OptionTypeEnum;
import com.mmall.pay.enums.PayPlatformTypeEnum;
import com.mmall.pay.enums.PayStatusEnum;
import com.mmall.pay.enums.PayTypeEnum;
import com.mmall.pay.exception.MmallPayException;
import com.mmall.pay.param.CloseOrderParam;
import com.mmall.pay.param.CreateOrderParam;
import com.mmall.pay.param.QueryOrderParam;
import com.mmall.pay.param.RefundParam;
import com.mmall.pay.param.RefundQueryParam;
import com.mmall.pay.result.CloseOrderResult;
import com.mmall.pay.result.CreateOrderResult;
import com.mmall.pay.result.QueryOrderResult;
import com.mmall.pay.result.RefundQueryResult;
import com.mmall.pay.result.RefundResult;
import com.mmall.pay.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;


/**
 * @author gg
 * @version WechatPayService.java, v 0.1 2019-05-27 17:23 gg
 */
@Slf4j
@Service("wechatPayService")
public class WechatPayServiceImpl implements PayService {

    @Resource
    private PaymentFlowService paymentFlowService;

    @Resource
    private PayConfigService payConfigService;


    @Override
    public QueryOrderResult queryOrder(QueryOrderParam queryOrderParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(queryOrderParam);
        WxPayService wxPayService = getWxService(mmallPayConfig);
        QueryOrderResult queryOrderResult;
        try {
            WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder("", queryOrderParam.getOutTradeNo().trim());
            queryOrderResult = BeanUtil.map(wxPayOrderQueryResult, QueryOrderResult.class);
        } catch (WxPayException e) {
            log.error("微信查询订单失败:orderNo:{},exception:{}", queryOrderParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return queryOrderResult;
    }

    @Override
    public CreateOrderResult createOrder(CreateOrderParam createOrderParam) throws MmallPayException {
        Date now = new Date();
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(createOrderParam);
        WxPayService wxPayService = getWxService(mmallPayConfig);
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(createOrderParam.getBody());
        orderRequest.setOutTradeNo(createOrderParam.getOutTradeNo().trim());
        orderRequest.setTotalFee(createOrderParam.getTotalFee());
        orderRequest.setSpbillCreateIp(createOrderParam.getIp());
        orderRequest.setTradeType(PayTypeEnum.getName(createOrderParam.getPayType()));
        orderRequest.setTimeStart(DateUtil.format(now, "yyyyMMddHHmmss"));
        orderRequest.setTimeExpire(DateUtil.format(DateUtil.offsetMinute(now, 5), "yyyyMMddHHmmss"));
        orderRequest.setAppid(mmallPayConfig.getAppId().trim());
        orderRequest.setMchId(mmallPayConfig.getPayMchId().trim());
        orderRequest.setSign(mmallPayConfig.getPaySign().trim());
        String openId = getOpenId(createOrderParam.getMemberId(), createOrderParam.getPublicId());
        orderRequest.setOpenid(openId);
        if (StringUtils.isNoneBlank(createOrderParam.getNotifyUrl())) {
            orderRequest.setNotifyUrl(createOrderParam.getNotifyUrl());
        }
        CreateOrderResult createOrderResult;
        try {
            WxPayMpOrderResult order = wxPayService.createOrder(orderRequest);
            createOrderResult = BeanUtil.map(order, CreateOrderResult.class);
            createOrderResult.setPlatform(PayPlatformTypeEnum.getName(createOrderParam.getPlatFormType()));
            createOrderResult.setOutTradeNo(createOrderParam.getOutTradeNo());
            createOrderResult.setPayType(PayTypeEnum.getName(createOrderParam.getType()));
            createOrderResult.setOpenId(openId);
            try {
                //插入流水
                paymentFlowService.addFlow(openId,
                        createOrderResult.getOutTradeNo(),
                        createOrderParam.getMemberId(),
                        createOrderParam.getMemberName(),
                        createOrderParam.getPlatFormType(),
                        createOrderParam.getType(),
                        OptionTypeEnum.PAY,
                        createOrderParam.getPublicId(),
                        createOrderParam.getTotalFee());
            } catch (Exception e) {
                log.error("微信支付流水记录失败,orderNo:{},exception:{}", createOrderParam.getOutTradeNo(), e);
            }
        } catch (WxPayException e) {
            log.error("微信支付异常:orderNo:{},exception:{}", createOrderParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return createOrderResult;
    }


    @Override
    public RefundResult refund(RefundParam refundParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(refundParam);
        WxPayService wxPayService = getWxService(mmallPayConfig);
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        wxPayRefundRequest.setOutTradeNo(refundParam.getOutTradeNo());
        wxPayRefundRequest.setOutRefundNo(refundParam.getOutRefundNo());
        wxPayRefundRequest.setTotalFee(refundParam.getTotalFee());
        wxPayRefundRequest.setRefundFee(refundParam.getRefundFee());
        wxPayRefundRequest.setRefundDesc(refundParam.getRefundDesc());
        wxPayRefundRequest.setOpUserId(mmallPayConfig.getPayMchId());
        wxPayRefundRequest.setAppid(mmallPayConfig.getAppId().trim());
        wxPayRefundRequest.setMchId(mmallPayConfig.getPayMchId().trim());
        wxPayRefundRequest.setSign(mmallPayConfig.getPaySign().trim());
        if (StringUtils.isNoneBlank(refundParam.getNotifyUrl())) {
            wxPayRefundRequest.setNotifyUrl(refundParam.getNotifyUrl());
        }
        RefundResult refundResult;
        String openId = getOpenId(refundParam.getMemberId(), refundParam.getPublicId());
        try {
            WxPayRefundResult refund = wxPayService.refund(wxPayRefundRequest);
            try {
                paymentFlowService.addFlow(openId,
                        refund.getOutTradeNo(),
                        refundParam.getMemberId(),
                        refundParam.getMemberName(),
                        refundParam.getPlatFormType(),
                        refundParam.getType(),
                        OptionTypeEnum.REFUND,
                        refundParam.getPublicId(),
                        refundParam.getTotalFee());
            } catch (Exception e) {
                log.error("微信退款流水记录失败,orderNo:{},exception:{}", refundParam.getOutTradeNo(), e);
            }
            refundResult = BeanUtil.map(refund, RefundResult.class);
        } catch (WxPayException e) {
            log.error("微信退款失败:orderNo:{},exception:{}", refundParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return refundResult;
    }

    @Override
    public RefundQueryResult refundQuery(RefundQueryParam refundQueryParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(refundQueryParam);
        WxPayService wxPayService = getWxService(mmallPayConfig);
        RefundQueryResult refundQueryResult;
        try {
            WxPayRefundQueryResult wxPayRefundQueryResult = wxPayService.refundQuery("", refundQueryParam.getOutTradeNo(), "", "");
            refundQueryResult = BeanUtil.map(wxPayRefundQueryResult, RefundQueryResult.class);
        } catch (WxPayException e) {
            log.error("微信退款查询失败:orderNo:{},exception:{}", refundQueryParam.getOutTradeNo(), e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return refundQueryResult;
    }

    @Override
    public CloseOrderResult closeOrder(CloseOrderParam closeOrderParam) throws MmallPayException {
        MmallPayConfig mmallPayConfig = payConfigService.selectByProductId(closeOrderParam);
        WxPayService wxPayService = getWxService(mmallPayConfig);
        CloseOrderResult closeOrderResult;
        try {
            WxPayOrderCloseResult wxPayOrderCloseResult = wxPayService.closeOrder(closeOrderParam.getOutTradeNo());
            closeOrderResult = BeanUtil.map(wxPayOrderCloseResult, CloseOrderResult.class);
        } catch (WxPayException e) {
            log.error("微信关闭订单失败:orderNo:{},exception:{}", e);
            throw BeanUtil.map(e, MmallPayException.class);
        }
        return closeOrderResult;
    }

    private String getOpenId(Long memberId, Long publicId) {
        //调用user 模块 接口 获取openId
        return null;
    }


    private WxPayService getWxService(MmallPayConfig mmallPayConfig) {
        WxPayConfig payConfig = new WxPayConfig();
        // 微信公众号或者小程序等的appId
        payConfig.setAppId(mmallPayConfig.getAppId());
        // 微信支付商户号mchId
        payConfig.setMchId(mmallPayConfig.getPayMchId());
        // 微信支付商户密钥mchKey
        payConfig.setMchKey(mmallPayConfig.getPaySign());
        payConfig.setKeyPath(mmallPayConfig.getKeyPath());
        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }


}
